//------------------------------------------------------------------------------
// <copyright file="Infer.cs" company="Microsoft">
//     
//      Copyright (c) 2006 Microsoft Corporation.  All rights reserved.
//     
//      The use and distribution terms for this software are contained in the file
//      named license.txt, which can be found in the root of this distribution.
//      By using this software in any fashion, you are agreeing to be bound by the
//      terms of this license.
//     
//      You must not remove this notice, or any other, from this software.
//     
// </copyright>
// <owner current="true" primary="true">priyal</owner> 
// <owner current="false" primary="false">nithyas</owner> 
//------------------------------------------------------------------------------

using System;
using System.IO;
using System.Xml;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Security.Permissions;




namespace System.Xml.Schema
 
{
        /// <include file='doc\Infer.uex' path='docs/doc[@for="Infer"]/*' />
        /// <summary>
        /// Infer class serves for infering XML Schema from given XML instance document.
        /// </summary>
        public sealed class XmlSchemaInference
        {
            internal static XmlQualifiedName ST_boolean = new XmlQualifiedName("boolean", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_byte = new XmlQualifiedName("byte", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_unsignedByte = new XmlQualifiedName("unsignedByte", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_short = new XmlQualifiedName("short", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_unsignedShort = new XmlQualifiedName("unsignedShort", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_int = new XmlQualifiedName("int", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_unsignedInt = new XmlQualifiedName("unsignedInt", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_long = new XmlQualifiedName("long", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_unsignedLong = new XmlQualifiedName("unsignedLong", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_integer = new XmlQualifiedName("integer", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_decimal = new XmlQualifiedName("decimal", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_float = new XmlQualifiedName("float", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_double = new XmlQualifiedName("double", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_duration = new XmlQualifiedName("duration", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_dateTime = new XmlQualifiedName("dateTime", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_time = new XmlQualifiedName("time", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_date = new XmlQualifiedName("date", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_gYearMonth = new XmlQualifiedName("gYearMonth", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_string = new XmlQualifiedName("string", XmlSchema.Namespace);
            internal static XmlQualifiedName ST_anySimpleType = new XmlQualifiedName("anySimpleType", XmlSchema.Namespace);

            internal static XmlQualifiedName[] SimpleTypes =
            {
                ST_boolean,
                ST_byte,
                ST_unsignedByte,
                ST_short,
                ST_unsignedShort,
                ST_int,
                ST_unsignedInt,
                ST_long,
                ST_unsignedLong,
                ST_integer,
                ST_decimal,
                ST_float,
                ST_double,
                ST_duration,
                ST_dateTime,
                ST_time,
                ST_date,
                ST_gYearMonth,
                ST_string
            };

            internal const short HC_ST_boolean = 0;
            internal const short HC_ST_byte = 1;
            internal const short HC_ST_unsignedByte = 2;
            internal const short HC_ST_short = 3;
            internal const short HC_ST_unsignedShort = 4;
            internal const short HC_ST_int = 5;
            internal const short HC_ST_unsignedInt = 6;
            internal const short HC_ST_long = 7;
            internal const short HC_ST_unsignedLong = 8;
            internal const short HC_ST_integer = 9;
            internal const short HC_ST_decimal = 10;
            internal const short HC_ST_float = 11;
            internal const short HC_ST_double = 12;
            internal const short HC_ST_duration = 13;
            internal const short HC_ST_dateTime = 14;
            internal const short HC_ST_time = 15;
            internal const short HC_ST_date = 16;
            internal const short HC_ST_gYearMonth = 17;
            internal const short HC_ST_string = 18;
            internal const short HC_ST_Count = HC_ST_string +1;
        
    
            internal const int TF_boolean = 1<<HC_ST_boolean;
            internal const int TF_byte = 1<<HC_ST_byte;
            internal const int TF_unsignedByte = 1<<HC_ST_unsignedByte;
            internal const int TF_short = 1<<HC_ST_short;
            internal const int TF_unsignedShort = 1<<HC_ST_unsignedShort;
            internal const int TF_int = 1<<HC_ST_int;
            internal const int TF_unsignedInt = 1<<HC_ST_unsignedInt;
            internal const int TF_long = 1<<HC_ST_long;
            internal const int TF_unsignedLong = 1<<HC_ST_unsignedLong;
            internal const int TF_integer = 1<<HC_ST_integer;
            internal const int TF_decimal = 1<<HC_ST_decimal;
            internal const int TF_float = 1<<HC_ST_float;
            internal const int TF_double = 1<<HC_ST_double;
            internal const int TF_duration = 1<<HC_ST_duration;
            internal const int TF_dateTime = 1<<HC_ST_dateTime;
            internal const int TF_time = 1<<HC_ST_time;
            internal const int TF_date = 1<<HC_ST_date;
            internal const int TF_gYearMonth = 1<<HC_ST_gYearMonth;
            internal const int TF_string = 1<<HC_ST_string;

            XmlSchema rootSchema = null; //(XmlSchema) xsc[TargetNamespace];
            private XmlSchemaSet schemaSet;
            private XmlReader xtr;
            private NameTable nametable;
            private string TargetNamespace;
            private XmlNamespaceManager NamespaceManager;
            //private Hashtable schemas;    //contains collection of schemas before they get added to the XmlSchemaSet xsc
            //private bool bRefine = false; //indicates if we are going to infer or refine schema when InferSchema is called
            ArrayList schemaList;
            InferenceOption occurrence = InferenceOption.Restricted;
            InferenceOption typeInference = InferenceOption.Restricted;

          /*  internal struct ReplaceList 
            {
                internal XmlSchemaObjectCollection col;
                internal int position;

                internal ReplaceList(XmlSchemaObjectCollection col, int position) 
                {
                    this.col = col;
                    this.position = position;
                }
            }*/

            /// <include file='doc\Infer.uex' path='docs/doc[@for="InferenceOption"]/*' />
            public enum InferenceOption 
            {
                /// <include file='doc\Infer.uex' path='docs/doc[@for="InferenceOption.Restricted"]/*' />
                Restricted,
                /// <include file='doc\Infer.uex' path='docs/doc[@for="InferenceOption.Relaxed"]/*' />
                Relaxed
            };

            /// <include file='doc\Infer.uex' path='docs/doc[@for="Infer.Occurrence"]/*' />
            public InferenceOption Occurrence 
            {
                set 
                {
                    this.occurrence = value;
                }
                get 
                {
                    return this.occurrence;
                }
            }
        
            /// <include file='doc\Infer.uex' path='docs/doc[@for="Infer.TypeInference"]/*' />
            public InferenceOption TypeInference 
            {
                set 
                {
                    this.typeInference = value;
                }
                get 
                {
                    return this.typeInference;
                }
            }

            /// <include file='doc\Infer.uex' path='docs/doc[@for="Infer.Infer"]/*' />
            public XmlSchemaInference()
            {
                this.nametable = new NameTable();
                this.NamespaceManager = new XmlNamespaceManager(nametable);
                this.NamespaceManager.AddNamespace("xs", XmlSchema.Namespace);
                this.schemaList = new ArrayList();
            }

            /// <include file='doc\Infer.uex' path='docs/doc[@for="Infer.InferSchema"]/*' />
            public XmlSchemaSet InferSchema(XmlReader instanceDocument)
            {
                return InferSchema1(instanceDocument, new XmlSchemaSet(nametable));
            }

            /// <include file='doc\Infer.uex' path='docs/doc[@for="Infer.InferSchema1"]/*' />
            public XmlSchemaSet InferSchema(XmlReader instanceDocument, XmlSchemaSet schemas)
            {
                if (schemas == null) 
                {
                    schemas = new XmlSchemaSet(nametable);
                }
                return InferSchema1(instanceDocument, schemas);
            }
            internal XmlSchemaSet InferSchema1(XmlReader instanceDocument, XmlSchemaSet schemas)
            {
                if (instanceDocument == null)
                {
                    throw new ArgumentNullException("instanceDocument");
                }
                this.rootSchema = null;
                xtr = instanceDocument;
                schemas.Compile();
                this.schemaSet = schemas;
                //schemas = new Hashtable();
                //while(xtr.Read())
               
                while (xtr.NodeType != XmlNodeType.Element && xtr.Read()) ;
             
                
                if (xtr.NodeType == XmlNodeType.Element)
                {
                    //Create and process the root element
                    TargetNamespace = xtr.NamespaceURI;
                    if ( xtr.NamespaceURI == XmlSchema.Namespace) 
                    {
                        throw new XmlSchemaInferenceException(Res.SchInf_schema, 0, 0);
                    }
                    XmlSchemaElement xse = null;
                    foreach (XmlSchemaElement elem in schemas.GlobalElements.Values) 
                    {
                        if (elem.Name == xtr.LocalName && elem.QualifiedName.Namespace == xtr.NamespaceURI) 
                        {
                            rootSchema = elem.Parent as XmlSchema;
                            xse = elem;
                            break;
                        }
                    }
                                                  
                    if (rootSchema == null) 
                    {
                        //rootSchema = CreateXmlSchema(xtr.NamespaceURI);
                        xse = AddElement(xtr.LocalName, xtr.Prefix, xtr.NamespaceURI, null, null, -1);
                    }
                    else 
                    { 
                        //bRefine = true;
                        InferElement(xse, false, rootSchema);
                    }
                        
                  /*  foreach (ReplaceList listItem in schemaList) 
                    {
                        if (listItem.position < listItem.col.Count) 
                        {
                            XmlSchemaElement particle = listItem.col[listItem.position] as XmlSchemaElement;
                            if (particle != null && (particle.RefName.Namespace == XmlSchema.Namespace)) 
                            {
                                XmlSchemaAny any = new XmlSchemaAny();
                                if (particle.MaxOccurs != 1) 
                                {
                                    any.MaxOccurs = particle.MaxOccurs;
                                }
                                if (particle.MinOccurs != 1)
                                {
                                    any.MinOccurs = particle.MinOccurs;
                                }
                                any.ProcessContents = XmlSchemaContentProcessing.Skip;
                                any.MinOccurs = decimal.Zero;
                                any.Namespace = particle.RefName.Namespace;
                                listItem.col[listItem.position] = any;
                            }
                        }
                    }*/
                    foreach(String prefix in this.NamespaceManager) 
                    {
                        if (!prefix.Equals("xml") && !prefix.Equals("xmlns"))
                        {
                            String ns = this.NamespaceManager.LookupNamespace(this.nametable.Get(prefix));
                            if (ns.Length != 0) { //Do not add xmlns=""
                                rootSchema.Namespaces.Add(prefix, ns);
                            }
                        }
                    }
                    Debug.Assert(this.rootSchema != null, "rootSchema is null");
                    schemas.Reprocess(rootSchema);
                    schemas.Compile();
                    //break;
                }
                else
                {
                    throw new XmlSchemaInferenceException(Res.SchInf_NoElement, 0, 0);
                }
                return schemas;
            }

            private XmlSchemaAttribute AddAttribute(string localName, string prefix, string childURI, string attrValue, bool bCreatingNewType, XmlSchema parentSchema, XmlSchemaObjectCollection addLocation, XmlSchemaObjectTable compiledAttributes)
            {
                if (childURI == XmlSchema.Namespace)
                {
                    throw new XmlSchemaInferenceException(Res.SchInf_schema, 0, 0);
                }

                XmlSchemaAttribute xsa = null;
                int AttributeType = -1;
                XmlSchemaAttribute returnedAttribute = null;    //this value will change to attributeReference if childURI!= parentURI
                XmlSchema xs = null;
                bool add = true;

                Debug.Assert(compiledAttributes != null); //AttributeUses is never null
                ICollection searchCollection;
                if (compiledAttributes.Count > 0) {
                    searchCollection = compiledAttributes.Values;
                }
                else {
                    searchCollection = addLocation; 
                }
                if (childURI == "http://www.w3.org/XML/1998/namespace")
                {
                    XmlSchemaAttribute attributeReference = null;
                    //see if the reference exists
                    attributeReference = FindAttributeRef(searchCollection, localName, childURI);
                    if (attributeReference == null)
                    {
                        attributeReference = new XmlSchemaAttribute();
                        attributeReference.RefName = new XmlQualifiedName(localName, childURI);
                        if (bCreatingNewType && this.Occurrence == InferenceOption.Restricted)
                        {
                            attributeReference.Use = XmlSchemaUse.Required;
                        }
                        else
                        {
                            attributeReference.Use = XmlSchemaUse.Optional;
                        }

                        addLocation.Add(attributeReference);
                    }
                    returnedAttribute = attributeReference;
                }
                else
                {
                    if (childURI.Length == 0)
                    {
                        xs = parentSchema;
                        add = false;
                    }
                    else if (childURI != null && !schemaSet.Contains(childURI))
                    {
                        /*if (parentSchema.AttributeFormDefault = XmlSchemaForm.Unqualified && childURI.Length == 0)
                    {
                        xs = parentSchema;
                        add = false;
                        break;
                    }*/
                        xs = new XmlSchema();
                        xs.AttributeFormDefault = XmlSchemaForm.Unqualified;
                        xs.ElementFormDefault = XmlSchemaForm.Qualified;
                        if (childURI.Length != 0)
                            xs.TargetNamespace = childURI;
                        //schemas.Add(childURI, xs);
                        this.schemaSet.Add(xs);
                        if (prefix.Length != 0 && String.Compare(prefix, "xml", StringComparison.OrdinalIgnoreCase) != 0)
                            NamespaceManager.AddNamespace(prefix, childURI);
                    }
                    else
                    {
                        ArrayList col = this.schemaSet.Schemas(childURI) as ArrayList;
                        if (col != null && col.Count > 0)
                        {
                            xs = col[0] as XmlSchema;
                        }

                    }
                    if (childURI.Length != 0)
                    {
                        XmlSchemaAttribute attributeReference = null;
                        //see if the reference exists
                        attributeReference = FindAttributeRef(searchCollection, localName, childURI);
                        if (attributeReference == null)
                        {
                            attributeReference = new XmlSchemaAttribute();
                            attributeReference.RefName = new XmlQualifiedName(localName, childURI);
                            if (bCreatingNewType && this.Occurrence == InferenceOption.Restricted)
                            {
                                attributeReference.Use = XmlSchemaUse.Required;
                            }
                            else
                            {
                                attributeReference.Use = XmlSchemaUse.Optional;
                            }

                            addLocation.Add(attributeReference);
                        }
                        returnedAttribute = attributeReference;

                        //see if the attribute exists on the global level
                        xsa = FindAttribute(xs.Items, localName);
                        if (xsa == null)
                        {
                            xsa = new XmlSchemaAttribute();
                            xsa.Name = localName;
                            xsa.SchemaTypeName = RefineSimpleType(attrValue, ref AttributeType);
                            xsa.LineNumber = AttributeType; //we use LineNumber to store flags of valid types
                            xs.Items.Add(xsa);

                        }
                        else
                        {
                            if (xsa.Parent == null)
                            {
                                AttributeType = xsa.LineNumber; // we use LineNumber to store flags of valid types
                            }
                            else
                            {
                                AttributeType = GetSchemaType(xsa.SchemaTypeName);
                                xsa.Parent = null;
                            }
                            xsa.SchemaTypeName = RefineSimpleType(attrValue, ref AttributeType);
                            xsa.LineNumber = AttributeType; // we use LineNumber to store flags of valid types
                        }
                    }
                    else
                    {
                        xsa = FindAttribute(searchCollection, localName);
                        if (xsa == null)
                        {
                            xsa = new XmlSchemaAttribute();
                            xsa.Name = localName;
                            xsa.SchemaTypeName = RefineSimpleType(attrValue, ref AttributeType);
                            xsa.LineNumber = AttributeType; // we use LineNumber to store flags of valid types
                            if (bCreatingNewType && this.Occurrence == InferenceOption.Restricted)
                                xsa.Use = XmlSchemaUse.Required;
                            else
                                xsa.Use = XmlSchemaUse.Optional;
                            addLocation.Add(xsa);
                            if (xs.AttributeFormDefault != XmlSchemaForm.Unqualified)
                            {
                                xsa.Form = XmlSchemaForm.Unqualified;
                            }
                        }
                        else
                        {
                            if (xsa.Parent == null)
                            {
                                AttributeType = xsa.LineNumber; // we use LineNumber to store flags of valid types
                            }
                            else
                            {
                                AttributeType = GetSchemaType(xsa.SchemaTypeName);
                                xsa.Parent = null;
                            }
                            xsa.SchemaTypeName = RefineSimpleType(attrValue, ref AttributeType);
                            xsa.LineNumber = AttributeType; // we use LineNumber to store flags of valid types
                        }
                        returnedAttribute = xsa;
                    }
                }
                string nullString = null;
                if (add && childURI != parentSchema.TargetNamespace)
                {
                    foreach (XmlSchemaExternal external in parentSchema.Includes)
                    {
                        XmlSchemaImport import = external as XmlSchemaImport;
                        if (import == null)
                        {
                            continue;
                        }
                        if (import.Namespace == childURI)
                        {
                            add = false;
                        }
                    }
                    if (add)
                    {
                        XmlSchemaImport import = new XmlSchemaImport();
                        import.Schema = xs;
                        if (childURI.Length != 0)
                        {
                            nullString = childURI;
                        }
                        import.Namespace = nullString;
                        parentSchema.Includes.Add(import);
                    }
                }


                return returnedAttribute;
            }

            private XmlSchema CreateXmlSchema(string targetNS) 
            {
                Debug.Assert(targetNS == null || targetNS.Length > 0 , "targetns for schema is empty");
                XmlSchema xs = new XmlSchema();
                xs.AttributeFormDefault = XmlSchemaForm.Unqualified;
                xs.ElementFormDefault = XmlSchemaForm.Qualified;
                xs.TargetNamespace = targetNS;
                this.schemaSet.Add(xs);
                return xs;
            }

            private XmlSchemaElement AddElement(string localName, string prefix, string childURI, XmlSchema parentSchema, XmlSchemaObjectCollection addLocation, int positionWithinCollection)
            {
                if (childURI == XmlSchema.Namespace)
                {
                    throw new XmlSchemaInferenceException(Res.SchInf_schema, 0, 0);
                }

                XmlSchemaElement xse = null;
                XmlSchemaElement returnedElement = xse; //this value will change to elementReference if childURI!= parentURI
                XmlSchema xs = null;
                bool bCreatingNewType = true;
                if (childURI == String.Empty) 
                {
                    childURI = null;
                }
                // The new element belongs to the same ns as parent and addlocation is not null
                if (parentSchema != null && childURI == parentSchema.TargetNamespace) 
                {
                    xse = new XmlSchemaElement();
                    xse.Name = localName;
                    xs = parentSchema;
                    if (xs.ElementFormDefault != XmlSchemaForm.Qualified && addLocation != null) 
                    {
                        xse.Form = XmlSchemaForm.Qualified;
                    }
                }
                else if (schemaSet.Contains(childURI))
                {
                    xse = this.FindGlobalElement(childURI, localName, out xs);
                    if (xse == null) 
                    {
                        ArrayList col = this.schemaSet.Schemas(childURI)as ArrayList;
                        if (col != null && col.Count > 0 ) 
                        {
                            xs = col[0] as XmlSchema;
                        }
                        xse = new XmlSchemaElement();
                        xse.Name = localName;
                        xs.Items.Add(xse);
                    }
                    else
                        bCreatingNewType = false;               

                }
                else
                {
                    xs = CreateXmlSchema(childURI);
                    if (prefix.Length!=0)
                        NamespaceManager.AddNamespace(prefix, childURI);
                    xse=new XmlSchemaElement();
                    xse.Name = localName;
                    xs.Items.Add(xse);  //add global element declaration only when creating new schema
                }
                if (parentSchema == null) 
                {
                    parentSchema = xs;
                    this.rootSchema = parentSchema;
                }

                if (childURI != parentSchema.TargetNamespace ) 
                {
                    bool add = true;
                   
                    foreach(XmlSchemaExternal external in parentSchema.Includes) 
                    {
                        XmlSchemaImport import = external as XmlSchemaImport;
                        if (import == null) 
                        {
                            continue;
                        }
                        //Debug.WriteLine(import.Schema.TargetNamespace);
                     
                        if (import.Namespace == childURI) 
                        {
                            add = false;
                        }
                    }
                    if (add) 
                    {
                        XmlSchemaImport import = new XmlSchemaImport();
                        import.Schema = xs;
                        import.Namespace = childURI;
                        parentSchema.Includes.Add(import);
                    }      
                }
                returnedElement = xse;
                if (addLocation != null)
                {
                    if (childURI == parentSchema.TargetNamespace )
                    {
                        if (this.Occurrence == InferenceOption.Relaxed /*&& parentSchema.Items != addLocation*/) 
                        {
                            xse.MinOccurs = 0;
                        }
                        if (positionWithinCollection == -1) 
                        {
                            positionWithinCollection = addLocation.Add(xse);
                        }
                        else 
                        {
                            addLocation.Insert(positionWithinCollection, xse);
                        }
                    }
                    else
                    {
                        XmlSchemaElement elementReference = new XmlSchemaElement();
                        elementReference.RefName = new XmlQualifiedName(localName, childURI);
                        if (this.Occurrence == InferenceOption.Relaxed) 
                        {
                            elementReference.MinOccurs = 0;
                        }
                        if (positionWithinCollection == -1) 
                        {
                            positionWithinCollection = addLocation.Add(elementReference);
                        }
                        else 
                        {
                            addLocation.Insert(positionWithinCollection, elementReference);
                        }
                        returnedElement = elementReference;
                       /* if (childURI == XmlSchema.Namespace) 
                        {
                            schemaList.Add(new ReplaceList(addLocation, positionWithinCollection));
                        }*/
                    }
                }
           

                InferElement(xse, bCreatingNewType, xs);
            
                return returnedElement;
            }

            /// <summary>
            /// Sets type of the xse based on the currently read element.
            /// If the type is already set, verifies that it matches the instance and if not, updates the type to validate the instance.
            /// </summary>
            /// <param name="xse">XmlSchemaElement corresponding to the element just read by the xtr XmlTextReader</param>
            /// <param name="bCreatingNewType">true if the type is newly created, false if the type already existed and matches the current element name</param>
            /// <param name="nsContext">namespaceURI of the parent element. Used to distinguish if ref= should be used when parent is in different ns than child.</param>
            internal void InferElement(XmlSchemaElement xse, bool bCreatingNewType, XmlSchema parentSchema)
            {
            
                bool bEmptyElement = xtr.IsEmptyElement;
                int lastUsedSeqItem = -1;

                Hashtable table = new Hashtable();
                XmlSchemaType schemaType = GetEffectiveSchemaType(xse, bCreatingNewType);
                XmlSchemaComplexType ct = schemaType as XmlSchemaComplexType;

                //infer type based on content of the current element
                if (xtr.MoveToFirstAttribute())
                {
                    ProcessAttributes(ref xse, schemaType, bCreatingNewType, parentSchema);
                }
                else
                {
                    if (!bCreatingNewType && ct != null) 
                    {   //if type already exists and can potentially have attributes
                        MakeExistingAttributesOptional(ct, null);
                    }
                }
                if (ct == null || ct == XmlSchemaComplexType.AnyType) { //It was null or simple type, after processing attributes, this might have been set
                    ct = xse.SchemaType as XmlSchemaComplexType;
                }
                //xse's type is set either to complex type if attributes exist or null
                if (bEmptyElement)  //<element attr="3232" />
                {
                    if (!bCreatingNewType)
                    {
                        if (null != ct)
                        {
                            if (null!= ct.Particle )

                            {
                                ct.Particle.MinOccurs = 0;
                            }
                            else if (null != ct.ContentModel)
                            {
                                XmlSchemaSimpleContentExtension sce = CheckSimpleContentExtension(ct);
                                sce.BaseTypeName = ST_string;
                                sce.LineNumber = TF_string;
                            }
                        }
                        else if (!xse.SchemaTypeName.IsEmpty)
                        {
                            xse.LineNumber = TF_string;
                            xse.SchemaTypeName = ST_string;
                        }
                    }
                    else
                    {
                        xse.LineNumber = TF_string;
                        //xse.SchemaTypeName = ST_string; //My change
                    }
                    return; //We are done processing this element - all attributes are already added
                }
                bool bWhiteSpace = false;
                do
                { 
                    xtr.Read();
                    if (xtr.NodeType == XmlNodeType.Whitespace) 
                    {
                        bWhiteSpace = true;
                    }
                    if (xtr.NodeType == XmlNodeType.EntityReference) 
                    {
                        throw new XmlSchemaInferenceException(Res.SchInf_entity, 0, 0);
                    }
                } while( (!xtr.EOF) && (xtr.NodeType != XmlNodeType.EndElement) && (xtr.NodeType != XmlNodeType.CDATA)&&(xtr.NodeType != XmlNodeType.Element)&&(xtr.NodeType != XmlNodeType.Text) );

                if (xtr.NodeType == XmlNodeType.EndElement)
                {
                    if (bWhiteSpace) {
                        if (ct != null)
                        {
                            if (null != ct.ContentModel)
                            {
                                XmlSchemaSimpleContentExtension sce = CheckSimpleContentExtension(ct);
                                sce.BaseTypeName = ST_string;
                                sce.LineNumber = TF_string;
                            }
                            else if (bCreatingNewType)
                            {
                                //attributes exist, but both Particle and ContentModel == null - this must be complex type with simpleContent extension
                                XmlSchemaSimpleContent sc = new XmlSchemaSimpleContent();
                                ct.ContentModel = sc;
                                XmlSchemaSimpleContentExtension sce = new XmlSchemaSimpleContentExtension();
                                sc.Content = sce;

                                MoveAttributes(ct, sce, bCreatingNewType);
                                
                                sce.BaseTypeName = ST_string;
                                sce.LineNumber = TF_string;
                            }
                            else
                                ct.IsMixed = true;
                        } 
                        else
                        {
                            xse.SchemaTypeName = ST_string;
                            xse.LineNumber = TF_string;
                        }
                    }
                    if (bCreatingNewType) 
                    {
                        xse.LineNumber = TF_string;
                        //xse.SchemaTypeName = ST_string; //my change
                    }
                    else
                    {
                        if (null != ct)
                        {
                            if (null!= ct.Particle) 
                            {
                                ct.Particle.MinOccurs = 0;
                            }
                            else if (null != ct.ContentModel)
                            {
                                XmlSchemaSimpleContentExtension sce = CheckSimpleContentExtension(ct);
                                sce.BaseTypeName = ST_string;
                                sce.LineNumber = TF_string;
                            }
                        }
                        else if (!xse.SchemaTypeName.IsEmpty)
                        {
                            xse.LineNumber = TF_string;
                            xse.SchemaTypeName = ST_string;
                        }
                    }

                    return; //<element attr="232"></element>
                }
                int iChildNumber = 0;
                bool bCreatingNewSequence = false;
                while (!xtr.EOF && (xtr.NodeType != XmlNodeType.EndElement))
                {
                    bool bNextNodeAlreadyRead = false;  //In some cases we have to look ahead one node. If true means that we did look ahead.
                    iChildNumber++;
                    if ((xtr.NodeType == XmlNodeType.Text) || (xtr.NodeType == XmlNodeType.CDATA) ) //node can be simple type, complex with simple content or complex with mixed content
                    {
                        if (null != ct)
                        {
                            if (null != ct.Particle)
                            {
                                ct.IsMixed = true;
                                if (iChildNumber==1)
                                {
                                    //if this is the only child and other elements do not follow, we must set particle minOccurs="0"
                                    do{ xtr.Read();} while( (!xtr.EOF) && ((xtr.NodeType == XmlNodeType.CDATA)||(xtr.NodeType == XmlNodeType.Text) ||  (xtr.NodeType == XmlNodeType.Comment) || (xtr.NodeType == XmlNodeType.ProcessingInstruction) || (xtr.NodeType == XmlNodeType.Whitespace) || (xtr.NodeType == XmlNodeType.SignificantWhitespace) || (xtr.NodeType == XmlNodeType.XmlDeclaration)));
                                    bNextNodeAlreadyRead = true;
                                    if (xtr.NodeType == XmlNodeType.EndElement)
                                        ct.Particle.MinOccurs=decimal.Zero;
                                }
                            }
                            else if (null!=ct.ContentModel)
                            {   //complexType with simpleContent
                                XmlSchemaSimpleContentExtension sce = CheckSimpleContentExtension(ct);
                                if ((xtr.NodeType == XmlNodeType.Text) && (iChildNumber==1))
                                {
                                    int SimpleType = -1;
                                    if (xse.Parent == null)
                                    {
                                        SimpleType = sce.LineNumber; // we use LineNumber to represent valid type flags
                                    }
                                    else
                                    {
                                        SimpleType = GetSchemaType(sce.BaseTypeName);
                                        xse.Parent = null;
                                    }
                                    sce.BaseTypeName = RefineSimpleType(xtr.Value, ref SimpleType);
                                    sce.LineNumber = SimpleType; // we use LineNumber to represent valid type flags
                                }
                                else
                                {
                                    sce.BaseTypeName = ST_string;
                                    sce.LineNumber = TF_string;
                                }
                            }
                            else
                            {
                                //attributes exist, but both Particle and ContentModel == null - this must be complex type with simpleContent extension
                                XmlSchemaSimpleContent sc = new XmlSchemaSimpleContent();
                                ct.ContentModel = sc;
                                XmlSchemaSimpleContentExtension sce = new XmlSchemaSimpleContentExtension();
                                sc.Content = sce;

                                MoveAttributes(ct, sce, bCreatingNewType);

                                if (xtr.NodeType == XmlNodeType.Text)
                                {
                                    int TypeFlags;
                                    if(!bCreatingNewType)
                                        //previously this was empty element
                                        TypeFlags=TF_string;
                                    else
                                        TypeFlags = -1;
                                    sce.BaseTypeName = RefineSimpleType(xtr.Value, ref TypeFlags);
                                    sce.LineNumber = TypeFlags; // we use LineNumber to store flags of valid types
                                }
                                else
                                {
                                    sce.BaseTypeName = ST_string;
                                    sce.LineNumber = TF_string;
                                }
                                
                            }
                        }
                        else
                        {   //node is currently empty or with SimpleType
                            //node will become simple type
                            if (iChildNumber>1)
                            {
                                //more than one consecutive text nodes probably with PI in between
                                xse.SchemaTypeName = ST_string;
                                xse.LineNumber = TF_string;// we use LineNumber to store flags of valid types
                            }
                            else
                            {
                                int TypeFlags = -1;
                                if (bCreatingNewType)
                                    if (xtr.NodeType == XmlNodeType.Text)
                                    {
                                        xse.SchemaTypeName = RefineSimpleType(xtr.Value, ref TypeFlags);
                                        xse.LineNumber = TypeFlags; // we use LineNumber to store flags of valid types
                                    }
                                    else
                                    {
                                        xse.SchemaTypeName = ST_string;
                                        xse.LineNumber = TF_string;// we use LineNumber to store flags of valid types
                                    }
                                else if (xtr.NodeType == XmlNodeType.Text)
                                {
                                    if (xse.Parent == null)
                                    {
                                        TypeFlags = xse.LineNumber;
                                    }
                                    else
                                    {
                                        TypeFlags = GetSchemaType(xse.SchemaTypeName);
                                        if (TypeFlags == -1 && xse.LineNumber == TF_string) { //Since schemaTypeName is not set for empty elements (<e></e>)
                                            TypeFlags = TF_string;
                                        }
                                        xse.Parent = null;
                                    }
                                    xse.SchemaTypeName = RefineSimpleType(xtr.Value, ref TypeFlags);    //simple type
                                    xse.LineNumber = TypeFlags; // we use LineNumber to store flags of valid types
                                }
                                else
                                {
                                    xse.SchemaTypeName = ST_string;
                                    xse.LineNumber = TF_string;// we use LineNumber to store flags of valid types
                                }
                            }
                        } 
                    }
                    else if (xtr.NodeType == XmlNodeType.Element)
                    {
                        XmlQualifiedName qname = new XmlQualifiedName(xtr.LocalName, xtr.NamespaceURI);
                        bool Maxoccursflag = false;
                        if (table.Contains(qname)) 
                        {
                            Maxoccursflag = true;
                        }
                        else 
                        {
                            table.Add(qname, null);
                        }
                        if (ct==null)
                        { //untill now the element was empty or SimpleType - it now becomes complex type
                            ct = new XmlSchemaComplexType();
                            xse.SchemaType = ct;
                            if (!xse.SchemaTypeName.IsEmpty)
                            {
                                ct.IsMixed=true;
                                xse.SchemaTypeName = XmlQualifiedName.Empty;
                            }
                        }
                        if (ct.ContentModel !=null)
                        {   //type was previously identified as simple content extension - we need to convert it to sequence
                            XmlSchemaSimpleContentExtension sce = CheckSimpleContentExtension(ct);
                            MoveAttributes(sce, ct);
                            ct.ContentModel = null;
                            ct.IsMixed = true;
                            if (ct.Particle != null)
                                throw new XmlSchemaInferenceException(Res.SchInf_particle, 0, 0);
                            ct.Particle = new XmlSchemaSequence();
                            bCreatingNewSequence = true;
                            XmlSchemaElement subelement = AddElement(xtr.LocalName, xtr.Prefix, xtr.NamespaceURI, parentSchema,((XmlSchemaSequence)ct.Particle).Items, -1);
                            lastUsedSeqItem = 0;
                            if (!bCreatingNewType)
                                ct.Particle.MinOccurs=0;    //previously this was simple type so subelements did not exist
                        }
                        else if (ct.Particle == null)
                        {
                            ct.Particle = new XmlSchemaSequence();
                            bCreatingNewSequence = true;
                            XmlSchemaElement subelement = AddElement(xtr.LocalName, xtr.Prefix, xtr.NamespaceURI, parentSchema,((XmlSchemaSequence)ct.Particle).Items, -1);
                            if (!bCreatingNewType)
                            {
                                ((XmlSchemaSequence)ct.Particle).MinOccurs = decimal.Zero;
                                //  subelement.MinOccurs = decimal.Zero;
                            }
                    
                            lastUsedSeqItem = 0;
                        }
                        else
                        {
                            bool bParticleChanged = false;
                            XmlSchemaElement subelement = FindMatchingElement(bCreatingNewType || bCreatingNewSequence, xtr, ct, ref lastUsedSeqItem, ref bParticleChanged, parentSchema, Maxoccursflag);
                        }
                    }
                    else if (xtr.NodeType == XmlNodeType.Text)
                    {
                        if (ct==null)
                            throw new XmlSchemaInferenceException(Res.SchInf_ct, 0, 0);
                        ct.IsMixed = true;
                    }
                    do
                    { 
                        if (xtr.NodeType == XmlNodeType.EntityReference)
                        {
                            throw new XmlSchemaInferenceException(Res.SchInf_entity, 0, 0);

                        }
                        if (!bNextNodeAlreadyRead)
                        {
                            xtr.Read();
                        }
                        else
                        {
                            bNextNodeAlreadyRead = false;
                        }
                    } while( (!xtr.EOF) && (xtr.NodeType != XmlNodeType.EndElement) && (xtr.NodeType != XmlNodeType.CDATA)&&(xtr.NodeType != XmlNodeType.Element)&&(xtr.NodeType != XmlNodeType.Text));
                }
                if (lastUsedSeqItem != -1)
                {
                    //Verify if all elements in a sequence exist, if not set MinOccurs=0
                    while (++lastUsedSeqItem < ((XmlSchemaSequence)ct.Particle).Items.Count)
                    {
                        if (((XmlSchemaSequence)ct.Particle).Items[lastUsedSeqItem].GetType() != typeof (XmlSchemaElement))
                            throw new XmlSchemaInferenceException(Res.SchInf_seq, 0 , 0);
                        XmlSchemaElement subElement = (XmlSchemaElement) ((XmlSchemaSequence)ct.Particle).Items[lastUsedSeqItem];
                        subElement.MinOccurs = 0;
                    }
                }

            }   
            
            private XmlSchemaSimpleContentExtension CheckSimpleContentExtension(XmlSchemaComplexType ct) {
                XmlSchemaSimpleContent sc = ct.ContentModel as XmlSchemaSimpleContent;
                if (sc == null) {
                    throw new XmlSchemaInferenceException(Res.SchInf_simplecontent, 0, 0);
                }
                XmlSchemaSimpleContentExtension sce = sc.Content as XmlSchemaSimpleContentExtension;
                if (sce == null) {
                    throw new XmlSchemaInferenceException(Res.SchInf_extension, 0, 0);
                }
                return sce;
            }

            private XmlSchemaType GetEffectiveSchemaType(XmlSchemaElement elem, bool bCreatingNewType) {
                XmlSchemaType effectiveSchemaType = null;
                if (!bCreatingNewType && elem.ElementSchemaType != null) {
                    effectiveSchemaType = elem.ElementSchemaType;
                }
                else { //creating new type, hence look up pre-compiled info
                    Debug.Assert(elem.ElementDecl == null);
                    if (elem.SchemaType != null) {
                        effectiveSchemaType = elem.SchemaType;
                    }
                    else if (elem.SchemaTypeName != XmlQualifiedName.Empty) {
                        effectiveSchemaType = schemaSet.GlobalTypes[elem.SchemaTypeName] as XmlSchemaType;
                        if (effectiveSchemaType == null) {
                            effectiveSchemaType = XmlSchemaType.GetBuiltInSimpleType(elem.SchemaTypeName);
                        }
                        if (effectiveSchemaType == null) {
                            effectiveSchemaType = XmlSchemaType.GetBuiltInComplexType(elem.SchemaTypeName);
                        }
                    }
                }
                return effectiveSchemaType;
            }
            /// <summary>
            /// Verifies that the current element has its corresponding element in the sequence and order is the same.
            /// If the order is not the same, it changes the particle from Sequence to Sequence with Choice.
            /// If there is more elements of the same kind in the sequence, sets maxOccurs to unbounded
            /// </summary>
            /// <param name="bCreatingNewType">True if this is a new type. This is important for setting minOccurs=0 for elements that did not exist in a particle.</param>
            /// <param name="xtr">text reader positioned to the current element</param>
            /// <param name="ct">complex type with Sequence or Choice Particle</param>
            /// <param name="lastUsedSeqItem">ordinal number in the sequence to indicate current sequence position</param>
            /// <param name="itemsMadeOptional">hashtable of elements with minOccurs changed to 0 in order to satisfy sequence requirements. These elements will be rolled back if Sequence becomes Sequence of Choice.</param>
            /// <param name="bParticleChanged">This indicates to the caller if Sequence was changed to Choice</param>
            internal XmlSchemaElement FindMatchingElement(bool bCreatingNewType, XmlReader xtr,XmlSchemaComplexType ct, ref int lastUsedSeqItem, ref bool bParticleChanged, XmlSchema parentSchema, bool setMaxoccurs)
            {
                if (xtr.NamespaceURI == XmlSchema.Namespace)
                {
                    throw new XmlSchemaInferenceException(Res.SchInf_schema, 0, 0);
                }

                bool bItemNotUsedYet = ((lastUsedSeqItem == -1)? true: false);
                XmlSchemaObjectCollection minOccursCandidates = new XmlSchemaObjectCollection(); //elements that are skipped in the sequence and need minOccurs modified.
                if (ct.Particle.GetType() == typeof (XmlSchemaSequence))
                {   
                    string childURI = xtr.NamespaceURI;
                    if (childURI.Length == 0) 
                    {
                        childURI = null;
                    }
                    XmlSchemaSequence xss = (XmlSchemaSequence) ct.Particle;
                    if (xss.Items.Count < 1 && !bCreatingNewType) 
                    {
                        lastUsedSeqItem = 0;
                        XmlSchemaElement e = AddElement(xtr.LocalName, xtr.Prefix, xtr.NamespaceURI, parentSchema, xss.Items,-1);
                        e.MinOccurs = 0;
                        return e;
                    }
                    if (xss.Items[0].GetType() == typeof (XmlSchemaChoice))
                    {   // <sequence minOccurs="0" maxOccurs="unbounded"><choice><element>...</choice></sequence>
                        XmlSchemaChoice xsch = (XmlSchemaChoice) xss.Items[0];
                        foreach(XmlSchemaParticle particle in xsch.Items)
                        {
                            XmlSchemaElement el = particle as XmlSchemaElement;
                            if (el == null) 
                            {
                                throw new XmlSchemaInferenceException(Res.SchInf_UnknownParticle, 0, 0);
                            }
                            if ((el.Name == xtr.LocalName) &&( parentSchema.TargetNamespace == childURI))
                            {   // element is in the same namespace
                                InferElement(el, false, parentSchema);
                                SetMinMaxOccurs(el, setMaxoccurs);
                                return el;
                            }
                            else if ((el.RefName.Name == xtr.LocalName) && (el.RefName.Namespace == xtr.NamespaceURI))
                            {
                                XmlSchemaElement referencedElement = FindGlobalElement(childURI, xtr.LocalName, out parentSchema);
                                InferElement(referencedElement, false, parentSchema);
                                SetMinMaxOccurs(el, setMaxoccurs);
                                return referencedElement;
                            }
                        }
                        XmlSchemaElement subElement = AddElement(xtr.LocalName, xtr.Prefix, xtr.NamespaceURI, parentSchema, xsch.Items,-1);
                        return subElement;
                    } 
                    else
                    {   //this should be sequence of elements
                        int iSeqItem = 0;   //iterator through schema sequence items
                        if (lastUsedSeqItem >= 0)
                            iSeqItem = lastUsedSeqItem;
                        XmlSchemaParticle particle = xss.Items[iSeqItem] as XmlSchemaParticle;
                        XmlSchemaElement el = particle as XmlSchemaElement;
                        if (el == null)
                        {
                            throw new XmlSchemaInferenceException(Res.SchInf_UnknownParticle, 0, 0);
                        }
                        if (el.Name == xtr.LocalName && parentSchema.TargetNamespace == childURI)
                        {
                            if (!bItemNotUsedYet)   //read: if item was already used one or more times
                                el.MaxOccurs = decimal.MaxValue;    //set it to unbounded
                            lastUsedSeqItem = iSeqItem;
                            InferElement(el, false, parentSchema);
                            SetMinMaxOccurs(el, false);
                            return el;
                        } 
                        else if (el.RefName.Name == xtr.LocalName && el.RefName.Namespace == xtr.NamespaceURI)
                        {
                            if (!bItemNotUsedYet)   //read: if item was already used one or more times
                                el.MaxOccurs = decimal.MaxValue;    //set it to unbounded
                            lastUsedSeqItem = iSeqItem;
                            XmlSchemaElement referencedElement = FindGlobalElement(childURI, xtr.LocalName, out parentSchema);
                            InferElement(referencedElement, false, parentSchema);
                            SetMinMaxOccurs(el, false);
                            return el;
                        }
                        if (bItemNotUsedYet && el.MinOccurs!=decimal.Zero)
                            minOccursCandidates.Add(el);
                        iSeqItem++;
                        while (iSeqItem < xss.Items.Count)
                        {
                            particle = xss.Items[iSeqItem] as XmlSchemaParticle;
                            el = particle as XmlSchemaElement;
                            if (el == null)
                            {
                                throw new XmlSchemaInferenceException(Res.SchInf_UnknownParticle, 0, 0);
                            }
                            if (el.Name == xtr.LocalName && parentSchema.TargetNamespace == childURI)
                            {
                                lastUsedSeqItem = iSeqItem;
                                foreach (XmlSchemaElement minOccursElement in minOccursCandidates)
                                    minOccursElement.MinOccurs = decimal.Zero;
                                InferElement(el, false, parentSchema);
                                SetMinMaxOccurs(el, setMaxoccurs);
                                return el;
                            } 
                            else if (el.RefName.Name == xtr.LocalName && el.RefName.Namespace == xtr.NamespaceURI)
                            {
                                lastUsedSeqItem = iSeqItem;
                                foreach (XmlSchemaElement minOccursElement in minOccursCandidates)
                                    minOccursElement.MinOccurs = decimal.Zero;
                                XmlSchemaElement referencedElement = FindGlobalElement(childURI, xtr.LocalName, out parentSchema);
                                InferElement(referencedElement, false, parentSchema);
                                SetMinMaxOccurs(el, setMaxoccurs);
                                return referencedElement;
                            }
                        

                            minOccursCandidates.Add(el);
                            iSeqItem++;
                        }

                        //element not found in the sequence order, if it is found out of order change Sequence of elements to Sequence of Choices otherwise insert into sequence as optional
                        XmlSchemaElement subElement = null;
                        XmlSchemaElement actualElement = null;
        
                        if (parentSchema.TargetNamespace == childURI) 
                        {
                            subElement = FindElement(xss.Items, xtr.LocalName);
                            actualElement = subElement;
                        }
                        else 
                        {
                            subElement = FindElementRef(xss.Items, xtr.LocalName, xtr.NamespaceURI);
                            if (subElement != null) 
                            {
                                actualElement = FindGlobalElement(childURI, xtr.LocalName, out parentSchema);
                            }
                        }
                        if (null != subElement) 
                        {
                            XmlSchemaChoice xsc = new XmlSchemaChoice();
                            xsc.MaxOccurs = decimal.MaxValue;
                            SetMinMaxOccurs(subElement, setMaxoccurs);
                            InferElement(actualElement, false, parentSchema);
                            foreach(XmlSchemaElement copyElement in xss.Items)
                            {
                                xsc.Items.Add(CreateNewElementforChoice(copyElement));
                            }
                            xss.Items.Clear();
                            xss.Items.Add(xsc);
                            return subElement;
                        }
                        else
                        {
                            subElement = AddElement(xtr.LocalName, xtr.Prefix, xtr.NamespaceURI, parentSchema, xss.Items, ++lastUsedSeqItem);
                            if (!bCreatingNewType)
                                subElement.MinOccurs = decimal.Zero;
                            return subElement;
                        }
                    }
                }
                else
                {
                    throw new XmlSchemaInferenceException(Res.SchInf_noseq, 0, 0);
                }
            
            }
            internal void ProcessAttributes(ref XmlSchemaElement xse, XmlSchemaType effectiveSchemaType, bool bCreatingNewType, XmlSchema parentSchema)
            {
                XmlSchemaObjectCollection attributesSeen = new XmlSchemaObjectCollection();
                XmlSchemaComplexType ct = effectiveSchemaType as XmlSchemaComplexType;
                
                Debug.Assert(xtr.NodeType == XmlNodeType.Attribute);
                do
                {
                    if (xtr.NamespaceURI == XmlSchema.Namespace)
                    {
                        throw new XmlSchemaInferenceException(Res.SchInf_schema, 0, 0);
                    }

                    if (xtr.NamespaceURI == "http://www.w3.org/2000/xmlns/")
                    {
                        if (xtr.Prefix=="xmlns") 
                            NamespaceManager.AddNamespace(xtr.LocalName, xtr.Value);
                    }
                    else if (xtr.NamespaceURI == "http://www.w3.org/2001/XMLSchema-instance")
                    {
                        string localName = xtr.LocalName;
                        if (localName == "nil") 
                        {
                            xse.IsNillable = true;
                        }
                        else if (localName != "type" && localName != "schemaLocation" && localName != "noNamespaceSchemaLocation")
                        {
                            throw new XmlSchemaInferenceException(Res.Sch_NotXsiAttribute,localName);
                        }
                    }
                    else
                    {
                        if (ct == null || ct == XmlSchemaComplexType.AnyType)
                        {
                            ct = new XmlSchemaComplexType();
                            xse.SchemaType = ct;
                        }

                        XmlSchemaAttribute xsa=null;
                        //The earlier assumption of checking just schemaTypeName !Empty is not correct for schemas that are not generated by us, schemaTypeName can point to any complex type as well
                        //Check that it is a simple type by checking typeCode
                        //Switch to complex type simple content extension
                        if (effectiveSchemaType != null && effectiveSchemaType.Datatype != null && !xse.SchemaTypeName.IsEmpty)  
                        {
                            //type was previously simple type, now it will become complex with simple type extension
                            Debug.Assert(ct != null);
                            XmlSchemaSimpleContent sc = new XmlSchemaSimpleContent();
                            ct.ContentModel = sc;
                            XmlSchemaSimpleContentExtension sce = new XmlSchemaSimpleContentExtension();
                            sc.Content = sce;
                            sce.BaseTypeName = xse.SchemaTypeName;
                            sce.LineNumber = xse.LineNumber;
                            xse.LineNumber = 0;
                            xse.SchemaTypeName = XmlQualifiedName.Empty; //re-set the name
                        }
                        
                        Debug.Assert(ct != null); //either the user-defined type itself is a complex type or we switched from a simple type to a complex type
                        if (ct.ContentModel != null) 
                        {
                            XmlSchemaSimpleContentExtension sce = CheckSimpleContentExtension(ct);
                            Debug.Assert(sce != null);
                            xsa = AddAttribute(xtr.LocalName, xtr.Prefix, xtr.NamespaceURI, xtr.Value, bCreatingNewType, parentSchema, sce.Attributes, ct.AttributeUses);
                        } 
                        else //add atributes directly to complex type
                        {
                            xsa = AddAttribute(xtr.LocalName, xtr.Prefix, xtr.NamespaceURI, xtr.Value, bCreatingNewType, parentSchema, ct.Attributes, ct.AttributeUses);
                        }
                        if (xsa != null) {
                            attributesSeen.Add(xsa);
                        }
                    }
                    
                } while (xtr.MoveToNextAttribute());
                if (!bCreatingNewType)
                {   
                    //make attributes that did not appear this time optional
                    if (ct!=null) {
                        MakeExistingAttributesOptional(ct, attributesSeen);
                    }
                }
            }
        
            private void MoveAttributes(XmlSchemaSimpleContentExtension scExtension,  XmlSchemaComplexType ct) {
                //copy all attributes from the simple content to the complex type
                //This is ok since when we move from complex type to simple content extension we copy from AttributeUses property
                foreach (XmlSchemaAttribute attr in scExtension.Attributes) { //since simpleContent is being cleared 
                    ct.Attributes.Add(attr);
                }
            }

            private void MoveAttributes(XmlSchemaComplexType ct, XmlSchemaSimpleContentExtension simpleContentExtension, bool bCreatingNewType) {
                //copy all attributes from the complex type to the simple content
                
                ICollection sourceCollection;
                if (!bCreatingNewType && ct.AttributeUses.Count > 0) {
                    sourceCollection = ct.AttributeUses.Values;
                }
                else {
                    sourceCollection = ct.Attributes;
                }
                
                foreach (XmlSchemaAttribute attr in sourceCollection) {
                    simpleContentExtension.Attributes.Add(attr);
                }
                ct.Attributes.Clear(); //Clear from pre-compiled property, post compiled will be cleared on Re-process and Compile()
            }

            internal XmlSchemaAttribute FindAttribute(ICollection attributes, string attrName)
            {
                foreach(XmlSchemaObject xsa in attributes)
                {
                    XmlSchemaAttribute schemaAttribute = xsa as XmlSchemaAttribute;
                    if (schemaAttribute != null)
                    {
                        if (schemaAttribute.Name == attrName)
                        {
                            return schemaAttribute;
                        }

                    }
                }
                return null;
            }

            internal XmlSchemaElement FindGlobalElement(string namespaceURI, string localName, out XmlSchema parentSchema)
            {
                ICollection col = this.schemaSet.Schemas(namespaceURI);
                XmlSchemaElement xse = null;
                parentSchema = null;
                foreach(XmlSchema schema in col) 
                {
                    xse = FindElement(schema.Items, localName);
                    if (xse != null) 
                    {
                        parentSchema = schema;
                        return xse;
                    }
                }
                return null;
            }


            internal XmlSchemaElement FindElement(XmlSchemaObjectCollection elements, string elementName)
            {
                foreach(XmlSchemaObject obj in elements)
                {
                    XmlSchemaElement xse = obj as XmlSchemaElement;
                    if (xse != null && xse.RefName != null)
                    {
                        if (xse.Name == elementName)
                        {
                            return xse;
                        }
                    }
                }
                return null;
            }

            internal XmlSchemaAttribute FindAttributeRef(ICollection attributes, string attributeName, string nsURI)
            {
                foreach(XmlSchemaObject xsa in attributes)
                {
                    XmlSchemaAttribute schemaAttribute = xsa as XmlSchemaAttribute;
                    if (schemaAttribute != null)
                    {
                        if (schemaAttribute.RefName.Name == attributeName && schemaAttribute.RefName.Namespace == nsURI) {
                            return schemaAttribute;
                        }
                        
                    }
                }
                return null;
            }

            internal XmlSchemaElement FindElementRef(XmlSchemaObjectCollection elements, string elementName, string nsURI)
            {
                foreach (XmlSchemaObject obj in elements)
                {
                    XmlSchemaElement xse = obj as XmlSchemaElement;
                    if (xse != null && xse.RefName != null)
                    {
                        if (xse.RefName.Name == elementName && xse.RefName.Namespace == nsURI)
                        {
                            return xse;
                        }
                    }
                }
                return null;
            }

            internal void MakeExistingAttributesOptional(XmlSchemaComplexType ct, XmlSchemaObjectCollection attributesInInstance) {
                if (ct == null)  {
                    throw new XmlSchemaInferenceException(Res.SchInf_noct, 0, 0);
                }
                if (ct.ContentModel != null) {
                    XmlSchemaSimpleContentExtension xssce = CheckSimpleContentExtension(ct);
                    SwitchUseToOptional(xssce.Attributes, attributesInInstance);
                }
                else { //either <xs:attribute> as child of xs:complexType or the attributes are within the content model
                    SwitchUseToOptional(ct.Attributes, attributesInInstance);
                }
            }

            private void SwitchUseToOptional(XmlSchemaObjectCollection attributes, XmlSchemaObjectCollection attributesInInstance) {
                foreach (XmlSchemaObject attrObj in attributes) {
                    if (attrObj is XmlSchemaAttribute) {
                        XmlSchemaAttribute attr = attrObj as XmlSchemaAttribute;
                        if (attributesInInstance != null) {
                            if (attr.RefName.Name.Length == 0) { //If the attribute is not present in this instance, make it optional
                                if (null == FindAttribute(attributesInInstance, attr.Name)) {
                                    attr.Use = XmlSchemaUse.Optional;
                                }
                            }
                            else {
                                if (null == FindAttributeRef(attributesInInstance, attr.RefName.Name, attr.RefName.Namespace)) {
                                    attr.Use = XmlSchemaUse.Optional;
                                }
                            }
                        }
                        else {
                            attr.Use = XmlSchemaUse.Optional;
                        }
                    }
                }
            }

            internal XmlQualifiedName RefineSimpleType(string s, ref int iTypeFlags) 
            {
                bool bNeedsRangeCheck = false;
                s = s.Trim();
                if (iTypeFlags == TF_string || this.typeInference == InferenceOption.Relaxed)
                    return ST_string;
                iTypeFlags &= InferSimpleType(s, ref bNeedsRangeCheck);
                if (iTypeFlags == TF_string)
                    return ST_string;
                if (bNeedsRangeCheck)
                {
                    if ((iTypeFlags & TF_byte) != 0)
                    {
                        try
                        {
                            XmlConvert.ToSByte(s);
                            //sbyte.Parse(s);
                            if ((iTypeFlags & TF_unsignedByte) != 0)
                                return ST_unsignedByte; //number is positive and fits byte -> it also fits unsignedByte
                            else
                                return ST_byte;
                        }
                        catch (FormatException)
                        {}
                        catch (OverflowException)
                        {} 
                        iTypeFlags &= (~TF_byte);
                    }
                    if ((iTypeFlags & TF_unsignedByte) != 0)
                    {
                        try
                        {
                            XmlConvert.ToByte(s);
                            //byte.Parse(s);
                            return ST_unsignedByte;
                        }
                        catch (FormatException)
                        {}
                        catch (OverflowException)
                        {} 
                        iTypeFlags &= (~TF_unsignedByte);
                    }
                    if ((iTypeFlags & TF_short) != 0)
                    {
                        try
                        {
                            XmlConvert.ToInt16(s);
                            //short.Parse(s);
                            if ((iTypeFlags & TF_unsignedShort) != 0)
                                return ST_unsignedShort;    //number is positive and fits short -> it also fits unsignedShort
                            else
                                return ST_short;
                        }
                        catch (FormatException)
                        {}
                        catch (OverflowException)
                        {} 
                        iTypeFlags &= (~TF_short);
                    }
                    if ((iTypeFlags & TF_unsignedShort) != 0)
                    {
                        try
                        {
                            XmlConvert.ToUInt16(s);
                            //ushort.Parse(s);
                            return ST_unsignedShort;
                        }
                        catch (FormatException)
                        {}
                        catch (OverflowException)
                        {} 
                        iTypeFlags &= (~TF_unsignedShort);
                    }
                    if ((iTypeFlags & TF_int) != 0)
                    {
                        try
                        {
                            XmlConvert.ToInt32(s);
                            //int.Parse(s);
                            if ((iTypeFlags & TF_unsignedInt) != 0)
                                return ST_unsignedInt;  //number is positive and fits int -> it also fits unsignedInt
                            else
                                return ST_int;
                        }
                        catch (FormatException)
                        {}
                        catch (OverflowException)
                        {} 
                        iTypeFlags &= (~TF_int);
                    }
                    if ((iTypeFlags & TF_unsignedInt) != 0)
                    {
                        try
                        {
                            XmlConvert.ToUInt32(s);
                            //uint.Parse(s);
                            return ST_unsignedInt;
                        }
                        catch (FormatException)
                        {}
                        catch (OverflowException)
                        {} 
                        iTypeFlags &= (~TF_unsignedInt);
                    }
                    if ((iTypeFlags & TF_long) != 0)
                    {
                        try
                        {
                            XmlConvert.ToInt64(s);
                            //long.Parse(s);
                            if ((iTypeFlags & TF_unsignedLong) != 0)
                                return ST_unsignedLong; //number is positive and fits long -> it also fits unsignedLong
                            else
                                return ST_long;
                        }
                        catch (FormatException)
                        {}
                        catch (OverflowException)
                        {} 
                        iTypeFlags &= (~TF_long);
                    }
                    if ((iTypeFlags & TF_unsignedLong) != 0)
                    {
                        try
                        {
                            XmlConvert.ToUInt64(s);
                            //ulong.Parse(s);
                            return ST_unsignedLong;
                        }
                        catch (FormatException)
                        {}
                        catch (OverflowException)
                        {}
                        iTypeFlags &= (~TF_unsignedLong);
                    }
                    if ((iTypeFlags & TF_float) != 0)
                    {
                        try
                        {
                            XmlConvert.ToSingle(s);
                            if ((iTypeFlags & TF_integer) != 0)
                                return ST_integer;
                            else if ((iTypeFlags & TF_decimal) != 0)
                                return ST_decimal;
                            else
                                return ST_float;
                        }
                        catch (FormatException)
                        {}
                        catch (OverflowException)
                        {}
                        iTypeFlags &= (~TF_float);
                    }
                    if ((iTypeFlags & TF_double) != 0)
                    {
                        try
                        {
                            XmlConvert.ToDouble(s);
                            if ((iTypeFlags & TF_integer) != 0)
                                return ST_integer;
                            else if ((iTypeFlags & TF_decimal) != 0)
                                return ST_decimal;
                            else
                                return ST_double;
                        }
                        catch (FormatException)
                        {}
                        catch (OverflowException)
                        {}
                        iTypeFlags &= (~TF_double);
                    }
                    if ((iTypeFlags & TF_integer) != 0)
                        return ST_integer;
                    else if ((iTypeFlags & TF_decimal) != 0)
                        return ST_decimal;
                    else if (iTypeFlags == (TF_gYearMonth | TF_string) )
                    {
                        try
                        {
                            XmlConvert.ToDateTime(s, XmlDateTimeSerializationMode.RoundtripKind);
                            return ST_gYearMonth;
                        }
                        catch (FormatException)
                        {}
                        catch (OverflowException)
                        {}
                        iTypeFlags = TF_string;
                        return ST_string;
                    }
                    else if (iTypeFlags == (TF_duration | TF_string) )
                    {
                        try
                        {
                            XmlConvert.ToTimeSpan(s);
                            return ST_duration;
                        }
                        catch (FormatException)
                        {}
                        catch (OverflowException)
                        {}
                        iTypeFlags = TF_string;
                        return ST_string;
                    }
                    else if (iTypeFlags == (TF_boolean | TF_string))
                    {
                        return ST_boolean;
                    }
                   
                }
               
                    switch (iTypeFlags)
                    {
                        case TF_string:
                            return ST_string;
                        case TF_boolean:
                            return ST_boolean;
                        case TF_byte:
                            return ST_byte;
                        case TF_unsignedByte:
                            return ST_unsignedByte;
                        case TF_short:
                            return ST_short;
                        case TF_unsignedShort:
                            return ST_unsignedShort;
                        case TF_int:
                            return ST_int;
                        case TF_unsignedInt:
                            return ST_unsignedInt;
                        case TF_long:
                            return ST_long;
                        case TF_unsignedLong:
                            return ST_unsignedLong;
                        case TF_integer:
                            return ST_integer;
                        case TF_decimal:
                            return ST_decimal;
                        case TF_float:
                            return ST_float;
                        case TF_double:
                            return ST_double;
                        case TF_duration:
                            return ST_duration;
                        case TF_dateTime:
                            return ST_dateTime;
                        case TF_time:
                            return ST_time;
                        case TF_date:
                            return ST_date;
                        case TF_gYearMonth:
                            return ST_gYearMonth;

                        case TF_boolean | TF_string:
                            return ST_boolean;
                        case TF_dateTime | TF_string:
                            return ST_dateTime;
                        case TF_date | TF_string:
                            return ST_date;
                        case TF_time | TF_string:
                            return ST_time;
                        case TF_float | TF_double | TF_string:
                            return ST_float;
                        case TF_double | TF_string:
                            return ST_double;

                        default:
                            Debug.Assert(false, "Expected type not matched");
                            return ST_string;
                    }
                /*          if (currentType == null)
                                return SimpleTypes[newType];
                            else
                                return SimpleTypes[ST_Map[newType,(short) ST_Codes[currentType]]];
                                */
            }

            internal static int InferSimpleType(string s, ref bool bNeedsRangeCheck) 
            {
                bool bNegative = false;
                bool bPositive = false;
                bool bDate = false;
                bool bTime = false;
                bool bMissingDay = false;

                if (s.Length==0) return TF_string;
                int i = 0;
                switch (s[i])
                {
                    case 't':
                    case 'f':
                        if (s == "true")
                            return TF_boolean | TF_string;
                        else if (s == "false")
                            return TF_boolean | TF_string;
                        else
                            return TF_string;
                    case 'N':       //try to match "NaN"
                        if (s == "NaN")
                            return TF_float | TF_double | TF_string;
                        else
                            return TF_string;
                        //else 
                    case 'I':       //try to match "INF"
                        INF:
                            if (s.Substring(i) == "INF")
                                return TF_float | TF_double | TF_string;
                            else return TF_string;
                    case '.':       //try to match ".9999"  decimal/float/double
                        FRACTION:
                            bNeedsRangeCheck = true;
                        i++;
                        if (i==s.Length)
                        {
                            if ((i==1) || (i==2 && (bPositive || bNegative)))   //"." "-." "+."
                                return TF_string;
                            else
                                return TF_decimal | TF_float | TF_double | TF_string;
                        }
                    switch (s[i])
                    {
                        case 'e':
                        case 'E':
                            goto EXPONENT;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto DEC_PART;
                            else
                                return TF_string;
                    }
                        DEC_PART:
                            i++; if (i==s.Length) return TF_decimal | TF_float | TF_double | TF_string; //"9999.9" was matched
                    switch (s[i])
                    {
                        case 'e':
                        case 'E':
                            goto EXPONENT;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto DEC_PART;
                            else
                                return TF_string;
                    }
                        EXPONENT:
                            i++; if (i==s.Length) return TF_string;
                    switch (s[i])
                    {
                        case '+':
                        case '-':
                            goto E1;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto EXP_PART;
                            else
                                return TF_string;
                    }
                        E1:
                            i++; if (i==s.Length) return TF_string; //".9999e+" was matched
                        if (s[i]>='0' && s[i]<='9')
                            goto EXP_PART;
                        else
                            return TF_string;   //".999e+X was matched
                        EXP_PART:
                            i++; if (i==s.Length) return TF_float | TF_double | TF_string;  //".9999e+99" was matched
                        if (s[i]>='0' && s[i]<='9') //".9999e+9
                            goto EXP_PART;
                        else
                            return TF_string;   //".9999e+999X" was matched
                    case '-':
                        bNegative = true;
                        i++; if (i==s.Length) return TF_string;
                    switch (s[i])
                    {
                        case 'I':   //try to match "-INF"
                            goto INF;
                        case '.':   //try to match "-.9999"
                            goto FRACTION;
                        case 'P':
                            goto DURATION;
                        default:
                            if (s[i]>='0' && s[i]<='9') //-9
                                goto NUMBER;
                            else return TF_string;
                    }
                    case '+':
                        bPositive = true;
                        i++; if (i==s.Length) return TF_string;
                    switch (s[i])
                    {
                        case '.':   //try to match "+.9999"
                            goto FRACTION;
                        case 'P':
                            goto DURATION;
                        default:
                            if (s[i]>='0' && s[i]<='9') //"+9
                                goto NUMBER;
                            else return TF_string;
                    }
                    case 'P':       //try to match duration
                        DURATION:
                            i++; if (i==s.Length) return TF_string;
                    switch (s[i])
                    {
                        case 'T':
                            goto D7;
                        default:
                            if (s[i]>='0' && s[i]<='9') //"P9"
                                goto D1;
                            else return TF_string;
                    }
                        D1:
                            i++; if (i==s.Length) return TF_string; //"P999" was matched
                    switch (s[i])
                    {
                        case 'Y':
                            goto D2;
                        case 'M':
                            goto D4;
                        case 'D':
                            goto D6;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto D1;
                            else
                                return TF_string;
                    }
                        D2:
                            i++; 
                        if (i==s.Length)
                        {
                            bNeedsRangeCheck = true;
                            return TF_duration | TF_string; //"P999Y" was matched
                        }
                    switch (s[i])
                    {
                        case 'T':
                            goto D7;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto D3;
                            else
                                return TF_string;
                    }
                        D3:
                            i++; if (i==s.Length) return TF_string; //"P999Y9" was matched
                    switch (s[i])
                    {
                        case 'M':
                            goto D4;
                        case 'D':
                            goto D6;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto D3;
                            else
                                return TF_string;
                    }
                        D4:
                            i++;
                        if (i==s.Length)
                        {
                            bNeedsRangeCheck = true;
                            return TF_duration | TF_string; //"P999Y999M" was matched
                        }
                    switch (s[i])
                    {
                        case 'T':
                            goto D7;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto D5;
                            else
                                return TF_string;
                    }
                        D5:
                            i++; if (i==s.Length) return TF_string; //"P999Y999M9" was matched
                    switch (s[i])
                    {
                        case 'D':
                            goto D6;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto D5;
                            else
                                return TF_string;
                    }
                        D6:
                            i++;
                        if (i==s.Length)
                        {
                            bNeedsRangeCheck = true;
                            return TF_duration | TF_string; //"P999Y999M999D" was matched
                        }
                    switch (s[i])
                    {
                        case 'T':
                            goto D7;
                        default:
                            return TF_string;
                    }
                        D7:
                            i++; if (i==s.Length) return TF_string; //"P999Y999M9999DT" was matched
                        if (s[i]>='0' && s[i]<='9')
                            goto D8;
                        else
                            return TF_string;
                        D8:
                            i++; if (i==s.Length) return TF_string; //"___T9" was matched
                    switch (s[i])
                    {
                        case 'H':
                            goto D9;
                        case 'M':
                            goto D11;
                        case '.':
                            goto D13;
                        case 'S':
                            goto D15;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto D8;
                            else
                                return TF_string;
                    }
                        D9:
                            i++;
                        if (i==s.Length)
                        {
                            bNeedsRangeCheck = true;
                            return TF_duration | TF_string; //"___T999H" was matched
                        }
                        if (s[i]>='0' && s[i]<='9')
                            goto D10;
                        else
                            return TF_string;
                        D10:
                            i++; if (i==s.Length) return TF_string; //"___T999H9" was matched
                    switch (s[i])
                    {
                        case 'M':
                            goto D11;
                        case '.':
                            goto D13;
                        case 'S':
                            goto D15;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto D10;
                            else
                                return TF_string;
                    }
                        D11:
                            i++;
                        if (i==s.Length)
                        {
                            bNeedsRangeCheck = true;
                            return TF_duration | TF_string; //"___T999H999M" was matched
                        }
                        if (s[i]>='0' && s[i]<='9')
                            goto D12;
                        else
                            return TF_string;
                        D12:
                            i++; if (i==s.Length) return TF_string; //"___T999H999M9" was matched
                    switch (s[i])
                    {
                        case '.':
                            goto D13;
                        case 'S':
                            goto D15;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto D12;
                            else
                                return TF_string;
                    }
                        D13:
                            i++;
                        if (i==s.Length)
                        {
                            bNeedsRangeCheck = true;
                            return TF_duration | TF_string; //"___T999H999M999." was matched
                        }
                        if (s[i]>='0' && s[i]<='9')
                            goto D14;
                        else
                            return TF_string;
                        D14:
                            i++; if (i==s.Length) return TF_string; //"___T999H999M999.9" was matched
                    switch (s[i])
                    {
                        case 'S':
                            goto D15;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto D14;
                            else
                                return TF_string;
                    }
                        D15:
                            i++;
                        if (i==s.Length)
                        {
                            bNeedsRangeCheck = true;
                            return TF_duration | TF_string; //"___T999H999M999.999S" was matched
                        }
                        else return TF_string;
                    case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
                        NUMBER:
                            i++;
                        if (i==s.Length)
                        {
                            bNeedsRangeCheck = true;
                            if (bNegative || bPositive)
                                return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string;  //"-9"
                            else
                            {
                                if (s=="0" || s=="1")
                                    return TF_boolean | TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
                                        TF_unsignedByte | TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
                                else
                                    return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
                                        TF_unsignedByte | TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
                            }
                        }
                    switch (s[i])
                    {
                        case '.':
                            goto FRACTION;
                        case 'e':
                        case 'E':
                            bNeedsRangeCheck = true;
                            return TF_float | TF_double | TF_string;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto N2;
                            else
                                return TF_string;
                    }
                        N2:
                            i++;
                        if (i==s.Length)
                        {
                            bNeedsRangeCheck = true;
                            if (bNegative || bPositive)
                                return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string;  //"-9"
                            else
                                return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
                                    TF_unsignedByte | TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
                        }
                    switch (s[i])
                    {
                        case '.':
                            goto FRACTION;
                        case ':':
                            bTime = true;
                            goto MINUTE;
                        case 'e':
                        case 'E':
                            bNeedsRangeCheck = true;
                            return TF_float | TF_double | TF_string;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto N3;
                            else
                                return TF_string;
                    }

                        N3:
                            i++;
                        if (i==s.Length)
                        {
                            bNeedsRangeCheck = true; //three digits may not fit byte and unsignedByte
                            if (bNegative || bPositive)
                                return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string;  //"-9"
                            else
                                return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
                                    TF_unsignedByte | TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
                        }
                    switch (s[i])
                    {
                        case '.':
                            goto FRACTION;
                        case 'e':
                        case 'E':
                            bNeedsRangeCheck = true;
                            return TF_float | TF_double | TF_string;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto N4;
                            else
                                return TF_string;
                    }
                        N4:
                            i++;
                        if (i==s.Length)
                        {
                            bNeedsRangeCheck = true;
                            if (bNegative || bPositive)
                                return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string;  //"-9"
                            else
                                return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
                                    TF_unsignedByte | TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
                        }

                    switch (s[i])
                    {
                        case '-':
                            bDate = true;
                            goto DATE;
                        case '.':
                            goto FRACTION;
                        case 'e':
                        case 'E':
                            bNeedsRangeCheck = true;
                            return TF_float | TF_double | TF_string;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto N4;
                            else
                                return TF_string;
                    }
                        DATE:
                            i++; if (i==s.Length) return TF_string; //"9999-"
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; if (i==s.Length) return TF_string; //"9999-9"
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++;
                        if (i==s.Length)
                        {
                            bNeedsRangeCheck = true;
                            return TF_gYearMonth | TF_string;   //"9999-99"
                        }
                    switch (s[i])
                    {
                        case '-':
                            goto DAY;
                        case 'Z':
                        case 'z':
                            bMissingDay = true;
                            goto ZULU;
                        case '+':
                            bMissingDay = true;
                            goto ZONE_SHIFT;
                        default:
                            return TF_string;
                    }
                        DAY:
                            i++; if (i==s.Length) return TF_string; //"9999-99-"
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; if (i==s.Length) return TF_string; //"9999-99-9"
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; if (i==s.Length) return DateTime(s, bDate, bTime); //"9999-99-99"
                    switch (s[i])
                    {
                        case 'Z':
                        case 'z':
                            goto ZULU;
                        case '+':
                        case '-':
                            goto ZONE_SHIFT;
                        case 'T':
                            bTime=true;
                            goto TIME;
                        case ':':
                            bMissingDay = true;
                            goto ZONE_SHIFT_MINUTE;
                        default:
                            return TF_string;
                    }
                        ZULU:   
                            i++; 
                        if (i==s.Length)
                        {
                            if (bMissingDay)
                            {
                                bNeedsRangeCheck=true;
                                return TF_gYearMonth | TF_string;
                            }
                            else
                            {
                                return DateTime(s, bDate, bTime);
                            }
                        }
                        else
                            return TF_string;
                        ZONE_SHIFT:
                            i++; if (i==s.Length) return TF_string;
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; if (i==s.Length) return TF_string;
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; if (i==s.Length) return TF_string;
                        if (s[i] != ':')
                            return TF_string;
                        ZONE_SHIFT_MINUTE:
                            i++; if (i==s.Length) return TF_string;
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; if (i==s.Length) return TF_string;
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; 
                        if (i==s.Length)
                        {
                            if (bMissingDay)
                            {
                                bNeedsRangeCheck=true;
                                return TF_gYearMonth | TF_string;
                            }
                            else
                            {
                                return DateTime(s, bDate, bTime);
                            }
                        }
                        else return TF_string;
                        TIME:
                            i++; if (i==s.Length) return TF_string;
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; if (i==s.Length) return TF_string;
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; if (i==s.Length) return TF_string;
                        if (s[i] != ':')
                            return TF_string;
                        MINUTE:
                            i++; if (i==s.Length) return TF_string;
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; if (i==s.Length) return TF_string;
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; if (i==s.Length) return TF_string;
                        if (s[i] != ':')
                            return TF_string;
                        i++; if (i==s.Length) return TF_string;
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; if (i==s.Length) return TF_string;
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        i++; if (i==s.Length) return DateTime(s, bDate, bTime);
                    switch (s[i])
                    {
                        case 'Z':
                        case 'z':
                            goto ZULU;
                        case '+':
                        case '-':
                            goto ZONE_SHIFT;
                        case '.':
                            goto SECOND_FRACTION;
                        default:
                            return TF_string;
                    }
                        SECOND_FRACTION:
                            i++; if (i==s.Length) return TF_string;
                        if (s[i]<'0' || s[i]>'9')
                            return TF_string;
                        FRACT_DIGITS:
                            i++; if (i==s.Length) return DateTime(s, bDate, bTime);
                    switch (s[i])
                    {
                        case 'Z':
                        case 'z':
                            goto ZULU;
                        case '+':
                        case '-':
                            goto ZONE_SHIFT;
                        default:
                            if (s[i]>='0' && s[i]<='9')
                                goto FRACT_DIGITS;
                            else
                                return TF_string;

                    }
                    default:
                        return TF_string;
                }
            }

            internal static int DateTime(string s, bool bDate, bool bTime)
            {
                try
                {
                    XmlConvert.ToDateTime(s, XmlDateTimeSerializationMode.RoundtripKind);
                }
                catch (FormatException)
                {
                    return TF_string;
                }
                if (bDate && bTime)
                    return TF_dateTime | TF_string;
                else if (bDate)
                    return TF_date | TF_string;
                else if (bTime)
                    return TF_time | TF_string;
                else
                {
                    Debug.Assert(false, "Expected date, time or dateTime");
                    return TF_string;
                }
            }
            XmlSchemaElement CreateNewElementforChoice(XmlSchemaElement copyElement) 
            {
                XmlSchemaElement newElement = new XmlSchemaElement();
                newElement.Annotation = copyElement.Annotation;
                newElement.Block = copyElement.Block;
                newElement.DefaultValue = copyElement.DefaultValue;
                newElement.Final = copyElement.Final;
                newElement.FixedValue = copyElement.FixedValue;
                newElement.Form = copyElement.Form;
                newElement.Id = copyElement.Id;
                //                newElement.IsAbstract = copyElement.IsAbstract;
                if (copyElement.IsNillable) 
                {
                    newElement.IsNillable = copyElement.IsNillable;
                }
                newElement.LineNumber = copyElement.LineNumber;
                newElement.LinePosition = copyElement.LinePosition;
                newElement.Name = copyElement.Name;
                newElement.Namespaces = copyElement.Namespaces;
                newElement.RefName = copyElement.RefName;
                newElement.SchemaType = copyElement.SchemaType;
                newElement.SchemaTypeName = copyElement.SchemaTypeName;
                newElement.SourceUri = copyElement.SourceUri;
                newElement.SubstitutionGroup = copyElement.SubstitutionGroup;
                newElement.UnhandledAttributes = copyElement.UnhandledAttributes;
                if (copyElement.MinOccurs != Decimal.One && this.Occurrence == InferenceOption.Relaxed) 
                {
                    newElement.MinOccurs = copyElement.MinOccurs;
                }
                if (copyElement.MaxOccurs != Decimal.One) {
                    newElement.MaxOccurs = copyElement.MaxOccurs;
                }
                return newElement;
            }

            private static int GetSchemaType(XmlQualifiedName qname)
            {
                if (qname == SimpleTypes[HC_ST_boolean])
                {
                    return TF_boolean | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_byte])
                {
                    return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_unsignedByte])
                {
                    return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
                                        TF_unsignedByte | TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_short])
                {
                    return TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_unsignedShort])
                {
                    return TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
                                         TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_int])
                {
                    return TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_unsignedInt])
                {
                    return  TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
                                          TF_unsignedInt | TF_unsignedLong | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_long])
                {
                    return TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_unsignedLong])
                {
                    return TF_long | TF_integer | TF_decimal | TF_float | TF_double |
                                          TF_unsignedLong | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_integer])
                {
                    return TF_integer |TF_decimal | TF_float | TF_double | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_decimal])
                {
                    return TF_decimal | TF_float | TF_double | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_float])
                {
                    return TF_float | TF_double | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_double])
                {
                    return TF_double | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_duration])
                {
                    return TF_duration | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_dateTime])
                {
                    return TF_dateTime | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_time])
                {
                    return TF_time | TF_string;
                }
                if (qname == SimpleTypes[HC_ST_date])
                {
                    return TF_date;
                }
                if (qname == SimpleTypes[HC_ST_gYearMonth])
                {
                    return TF_gYearMonth;
                }
                if (qname == SimpleTypes[HC_ST_string])
                {
                    return TF_string;
                }
                if (qname == null || qname.IsEmpty) {
                    return -1;
                }
                throw new XmlSchemaInferenceException(Res.SchInf_schematype, 0, 0);
            }

            internal void SetMinMaxOccurs(XmlSchemaElement el, bool setMaxOccurs)
            {
                if (this.Occurrence == InferenceOption.Relaxed)
                {
                    if (setMaxOccurs || el.MaxOccurs > 1)
                    {
                        el.MaxOccurs = decimal.MaxValue;    //set it to unbounded
                    }
                    el.MinOccurs = 0;
                }
                else if (el.MinOccurs > 1)
                {
                    el.MinOccurs = 1;
                }
            }


        }
    }
